#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include "od_udp_recv.h"
#include "od_rtp_unpack.h"
#include "od_rtp_pack.h"
#include "decoder_param.h"
#include "od_rtp_pack_common.h"
#include "retrans_send.h"
#include "HisiDecEncCtrl.h"
#include "HisiDecSendStream.h"
#include "HisiEncGetStream.h"
#include "usecase_decoder.h"
#include "params_id_def.h"
#include "HisiDecVpssOutDynamicSet.h"


static int chnCfgDone = OD_FALSE;

typedef struct connect_str_s
{
    char str[OD_MAX_PATH_LEN];
}connect_str_t;


uint64_t get_clock()
{
    struct timespec tv;
    uint64_t time = 0;

    if(clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
    {
        return 0;
    }

    time = (tv.tv_sec * 1000000000u + tv.tv_nsec) / 1000000;
    return time;
}

static void get_90k_clock(uint64_t *time)
{
    *time = get_clock() * 90;
}

static void * udp_recv_vid_static_create(void * usr, char * task_name)
{
    udp_recv_static_params_t * thr_static_params = NULL;

    thr_static_params = (udp_recv_static_params_t *)od_malloc(sizeof(udp_recv_static_params_t));
    if(NULL == thr_static_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }
    *thr_static_params = glb_udp_recv_static_params_default;
    strncpy(thr_static_params->task_name, task_name, OD_MAX_OBJ_NAME - 1);
    thr_static_params->buf_nums = 200;
    thr_static_params->memery_reduced = OD_OFF;

    return (void *)thr_static_params;
}

static void * udp_recv_vid_dynamic_create(void * usr)
{
    udp_recv_dynamic_params_t * thr_dynamic_params = NULL;

    thr_dynamic_params = (udp_recv_dynamic_params_t *)od_malloc(sizeof(udp_recv_dynamic_params_t));
    if(NULL == thr_dynamic_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }

    *thr_dynamic_params = glb_udp_recv_dynamic_params_default;
    thr_dynamic_params->recv_enable = OD_ON;
    thr_dynamic_params->recv_method = SOCK_UDP;
    thr_dynamic_params->recv_cast_mode = UDP_SOCKET_UNICAST;
    strncpy(thr_dynamic_params->recv_multi_addr, "224.1.1.1", UDP_ADDR_STR_LEN -1 );
    thr_dynamic_params->recv_port = 30000;
    strncpy(thr_dynamic_params->local_addr, "172.16.60.167", UDP_ADDR_STR_LEN -1 );

    return (void *)thr_dynamic_params;
}

static void * rtp_unpack_static_create(void *usr, char *task_name)
{
    od_rtp_unpack_static_params *static_params = NULL;

    static_params = (od_rtp_unpack_static_params *)od_malloc(sizeof(od_rtp_unpack_static_params));
    if(NULL == static_params)
    {
        RPTERR("malloc falied");
        return NULL;
    }

    *static_params = glb_od_rtp_unpack_static_params_default;

    static_params->vid_tube_bufnums = 10;
    static_params->vid_tube_bufsize = 1024*768;

    static_params->aud_tube_bufnums = 0;
    static_params->aud_tube_bufsize = 0;
    static_params->memery_reduced = OD_OFF;

    strncpy(static_params->task_name, task_name, OD_MAX_OBJ_NAME - 1);

    return static_params;
}

static void *hisi_dec_enc_ctl_static_create(void * usr, char * task_name)
{
    hisiDecEncCtrl_static_params * thr_static_params = NULL;
    decoder_params_obj * params_obj = usr;

    thr_static_params = (hisiDecEncCtrl_static_params *)od_malloc(sizeof(hisiDecEncCtrl_static_params));
    if(NULL == thr_static_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }
    *thr_static_params = glb_hisiDecEncCtrl_static_params_default;
    thr_static_params->task_name = task_name;
    thr_static_params->config_done = &chnCfgDone;
    thr_static_params->enVoMode = params_obj->dec_params.vdec.enVoMode;

    return (void *)thr_static_params;
}

static void * hisi_dec_enc_ctl_dynamic_create(void * usr)
{
    hisiDecEncCtrl_dynamic_params * thr_dynamic_params = NULL;

    thr_dynamic_params = (hisiDecEncCtrl_dynamic_params *)od_malloc(sizeof(hisiDecEncCtrl_dynamic_params));
    if(NULL == thr_dynamic_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }

    *thr_dynamic_params = glb_hisiDecEncCtrl_dynamic_params_default;

    return (void *)thr_dynamic_params;
}

static void *hisi_dec_static_create(void * usr, char * task_name)
{
    hisi_dec_static_params * thr_static_params = NULL;
    static int idx = 0;

    thr_static_params = (hisi_dec_static_params *)od_malloc(sizeof(hisi_dec_static_params));
    if(NULL == thr_static_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }
    *thr_static_params = glb_hisi_dec_static_params_default;
    thr_static_params->task_name = task_name;
    thr_static_params->u32Chn = idx++;

    return (void *)thr_static_params;
}

static void * hisi_dec_dynamic_create(void * usr)
{
    hisi_dec_dynamic_params * thr_dynamic_params = NULL;

    thr_dynamic_params = (hisi_dec_dynamic_params *)od_malloc(sizeof(hisi_dec_dynamic_params));
    if(NULL == thr_dynamic_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }

    *thr_dynamic_params = glb_hisi_dec_dynamic_params_default;

    return (void *)thr_dynamic_params;
}

static void *hisi_dynaimc_set_static_create(void * usr, char * task_name)
{
    HiMPP_static_params * thr_static_params = NULL;

    thr_static_params = (HiMPP_static_params *)od_malloc(sizeof(HiMPP_static_params));
    if(NULL == thr_static_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }
    *thr_static_params = glb_HiMPP_static_params_default;
    thr_static_params->task_name = task_name;
    thr_static_params->config_done = &chnCfgDone;

    return (void *)thr_static_params;
}

static void * hisi_dynaimc_set_dynamic_create(void * usr)
{
    HiMPP_dynamic_params * thr_dynamic_params = NULL;

    thr_dynamic_params = (HiMPP_dynamic_params *)od_malloc(sizeof(HiMPP_dynamic_params));
    if(NULL == thr_dynamic_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }

    *thr_dynamic_params = glb_HiMPP_dynamic_params_default;

    return (void *)thr_dynamic_params;
}


static void * rtp_pack_avc_static_create(void *usr, const char * task_name)
{
    od_rtp_pack_avc_static_params *static_params = NULL;

    static_params = (od_rtp_pack_avc_static_params *)od_malloc(sizeof(od_rtp_pack_avc_static_params));
    if(NULL == static_params)
    {
        RPTERR("%s static_params malloc falied", TSK_RTP_PACK_AVC);
        return NULL;
    }

    *static_params = glb_od_rtp_pack_avc_static_params_default;
    strncpy(static_params->task_name, task_name, OD_MAX_OBJ_NAME - 1);
    static_params->memery_reduced = OD_OFF;

    return static_params;
}

static void * rtp_pack_avc_dynamic_create(void *usr)
{
    od_rtp_pack_avc_dynamic_params *dynamic_params = NULL;

    dynamic_params = (od_rtp_pack_avc_dynamic_params *)od_malloc(sizeof(od_rtp_pack_avc_dynamic_params));
    if (NULL == dynamic_params)
    {
        RPTERR("%s dynamic_params malloc falied", TSK_RTP_PACK_AVC);
        return NULL;
    }
    
    *dynamic_params = glb_od_rtp_pack_avc_dynamic_params_default;

    dynamic_params->ctrl = OD_ON;
    dynamic_params->multi_video_ctrl = OD_OFF;
    dynamic_params->payload_type = 96;
    dynamic_params->limit_len = RTP_PKT_MAX_LEN;

    return dynamic_params;
}

static void * retransfer_send_static_create(void *usr, const char * task_name)
{
    retransfer_send_static_params *static_params = NULL;

    static_params = (retransfer_send_static_params *)od_malloc(sizeof(retransfer_send_static_params));
    if(NULL == static_params)
    {
        RPTERR("%s static_params malloc falied", TSK_VID_RETRANS_SEND);
        return NULL;
    }

    *static_params = glb_retransfer_send_static_params_default;

    static_params->get_stc_90k = get_90k_clock;
    strncpy(static_params->task_name, task_name, OD_MAX_OBJ_NAME - 1);

    return static_params;
}

static void * retransfer_send_dynamic_create(void *usr)
{
    retransfer_send_dynamic_params *dynamic_params = NULL;

    dynamic_params = (retransfer_send_dynamic_params *)od_malloc(sizeof(retransfer_send_dynamic_params));
    if (NULL == dynamic_params)
    {
        RPTERR("%s dynamic_params malloc falied", TSK_VID_RETRANS_SEND);
        return NULL;
    }
    
    *dynamic_params = glb_retransfer_send_dynamic_params_default;

    dynamic_params->send_enable = OD_ON;
    dynamic_params->retrans_enable = OD_OFF;
    strncpy(dynamic_params->local_ip, "172.16.60.167", UDP_ADDR_STR_LEN - 1);
    strncpy(dynamic_params->send_ip, "172.16.60.63", UDP_ADDR_STR_LEN - 1);
    dynamic_params->send_port = 6000;
    dynamic_params->sys_band = 2900;
    dynamic_params->buf_nums = 1024;//重传池大小

    return dynamic_params;
}

static void *hisi_enc_get_stream_static_create(void * usr, char * task_name)
{
    hisiEncGetStream_static_params * thr_static_params = NULL;

    thr_static_params = (hisiEncGetStream_static_params *)od_malloc(sizeof(hisiEncGetStream_static_params));
    if(NULL == thr_static_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }
    *thr_static_params = glb_hisiEncGetStream_static_params_default;
    thr_static_params->task_name = task_name;
    thr_static_params->VeChn = 0;
    thr_static_params->bufsize = 300 * 1024;
    thr_static_params->buf_nums = 100;

    return (void *)thr_static_params;
}

static void * hisi_enc_get_stream_dynamic_create(void * usr)
{
    hisiEncGetStream_dynamic_params * thr_dynamic_params = NULL;

    thr_dynamic_params = (hisiEncGetStream_dynamic_params *)od_malloc(sizeof(hisiEncGetStream_dynamic_params));
    if(NULL == thr_dynamic_params)
    {
        RPT(RPT_ERR, "NULL pointer, error");
        return NULL;
    }

    *thr_dynamic_params = glb_hisiEncGetStream_dynamic_params_default;

    return (void *)thr_dynamic_params;
}


static const app_task_spawn_info_t app_list[]=
{
    /**
        MAX 9 channel UDP receive!!
    */
    {TSK_UDP_RECV_VID(0), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(1), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(2), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(3), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(4), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(5), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(6), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(7), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },
    {TSK_UDP_RECV_VID(8), 87,
        (void *)udp_recv_vid_static_create, (void *)udp_recv_vid_dynamic_create, (void *)udp_recv_create,
    },


    /**
        MAX 9 channel RTP unpack!!!
    */
    {TSK_RTP_UNPACK(0), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(1), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(2), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(3), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(4), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(5), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(6), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(7), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },
    {TSK_RTP_UNPACK(8), 87,
        (void *)rtp_unpack_static_create, NULL, (void *)od_rtp_unpack_create,
    },


    /**
        MAX 9 channel send stream to HiMPP modules!!!
    */
    {TSK_HISI_DEC_SEND_STREAM(0), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(1), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(2), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(3), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(4), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(5), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(6), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(7), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },
    {TSK_HISI_DEC_SEND_STREAM(8), 87,
        (void *)hisi_dec_static_create, hisi_dec_dynamic_create, (void *)hisi_dec_create,
    },

    /**
        get the consist picture to video enc thread！
    */
    {TSK_HISI_DEC_ENC_CTL, 87,
        (void *)hisi_dec_enc_ctl_static_create, hisi_dec_enc_ctl_dynamic_create, (void *)hisiDecEncCtrl_create,
    },

    {TSK_HISI_HIMPP_DYNAMIC_SET, 87,
        (void *)hisi_dynaimc_set_static_create, hisi_dynaimc_set_dynamic_create, (void *)HiMPP_create,
    },


    /**
        getES--->RTP---->UDPsend
    */
    {TSK_HISI_ENC_GET_STREAM, 60,
        (void *)hisi_enc_get_stream_static_create, hisi_enc_get_stream_dynamic_create, (void *)hisiEncGetStream_create
    },
    {TSK_RTP_PACK_AVC, 87, 
        (void *)rtp_pack_avc_static_create, rtp_pack_avc_dynamic_create, (void *)od_rtp_pack_avc_create,
    },
    {TSK_VID_RETRANS_SEND, 60,
        (void *)retransfer_send_static_create, retransfer_send_dynamic_create, (void *)retransfer_send_create
    },

    {"", 0,
        NULL, NULL, NULL,
    }

};

static task_name_t  decoder_starting_list[] =
{
    /* video */
    {TSK_HISI_DEC_ENC_CTL},
    {TSK_HISI_HIMPP_DYNAMIC_SET},

    {TSK_VID_RETRANS_SEND},
    {TSK_RTP_PACK_AVC},
    {TSK_HISI_ENC_GET_STREAM},
        
    {TSK_HISI_DEC_SEND_STREAM(0)},
    {TSK_RTP_UNPACK(0)},
    {TSK_UDP_RECV_VID(0)},
        
    {TSK_HISI_DEC_SEND_STREAM(1)},
    {TSK_RTP_UNPACK(1)},
    {TSK_UDP_RECV_VID(1)},

    {TSK_HISI_DEC_SEND_STREAM(2)},
    {TSK_RTP_UNPACK(2)},
    {TSK_UDP_RECV_VID(2)},

    {TSK_HISI_DEC_SEND_STREAM(3)},
    {TSK_RTP_UNPACK(3)},
    {TSK_UDP_RECV_VID(3)},
        
    {TSK_HISI_DEC_SEND_STREAM(4)},
    {TSK_RTP_UNPACK(4)},
    {TSK_UDP_RECV_VID(4)},

    {TSK_HISI_DEC_SEND_STREAM(5)},
    {TSK_RTP_UNPACK(5)},
    {TSK_UDP_RECV_VID(5)},

    {TSK_HISI_DEC_SEND_STREAM(6)},
    {TSK_RTP_UNPACK(6)},
    {TSK_UDP_RECV_VID(6)},

    {TSK_HISI_DEC_SEND_STREAM(7)},
    {TSK_RTP_UNPACK(7)},
    {TSK_UDP_RECV_VID(7)},

    {TSK_HISI_DEC_SEND_STREAM(8)},
    {TSK_RTP_UNPACK(8)},
    {TSK_UDP_RECV_VID(8)},
};

static connect_str_t  decoder_connect_list[] =
{
    /* video decode*/
    {TSK_UDP_RECV_VID(0)".out->"TSK_RTP_UNPACK(0)".vid_in"},
    {TSK_RTP_UNPACK(0)".vid_out->"TSK_HISI_DEC_SEND_STREAM(0)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(1)".out->"TSK_RTP_UNPACK(1)".vid_in"},
    {TSK_RTP_UNPACK(1)".vid_out->"TSK_HISI_DEC_SEND_STREAM(1)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(2)".out->"TSK_RTP_UNPACK(2)".vid_in"},
    {TSK_RTP_UNPACK(2)".vid_out->"TSK_HISI_DEC_SEND_STREAM(2)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(3)".out->"TSK_RTP_UNPACK(3)".vid_in"},
    {TSK_RTP_UNPACK(3)".vid_out->"TSK_HISI_DEC_SEND_STREAM(3)"."DEC_SEND_STREAM_IN_ES_NAME},
        
    {TSK_UDP_RECV_VID(4)".out->"TSK_RTP_UNPACK(4)".vid_in"},
    {TSK_RTP_UNPACK(4)".vid_out->"TSK_HISI_DEC_SEND_STREAM(4)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(5)".out->"TSK_RTP_UNPACK(5)".vid_in"},
    {TSK_RTP_UNPACK(5)".vid_out->"TSK_HISI_DEC_SEND_STREAM(5)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(6)".out->"TSK_RTP_UNPACK(6)".vid_in"},
    {TSK_RTP_UNPACK(6)".vid_out->"TSK_HISI_DEC_SEND_STREAM(6)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(7)".out->"TSK_RTP_UNPACK(7)".vid_in"},
    {TSK_RTP_UNPACK(7)".vid_out->"TSK_HISI_DEC_SEND_STREAM(7)"."DEC_SEND_STREAM_IN_ES_NAME},

    {TSK_UDP_RECV_VID(8)".out->"TSK_RTP_UNPACK(8)".vid_in"},
    {TSK_RTP_UNPACK(8)".vid_out->"TSK_HISI_DEC_SEND_STREAM(8)"."DEC_SEND_STREAM_IN_ES_NAME},

    /* video encode & send*/
    {TSK_HISI_ENC_GET_STREAM"."ENC_GET_STREAM_NAME "->" TSK_RTP_PACK_AVC".in"},
    {TSK_RTP_PACK_AVC".vid_out""->" TSK_VID_RETRANS_SEND"."RETRANS_SEND_TUBE_IN_NAME},
};


int32_t decoder_start(od_framework_t * framework)
{
    int32_t ret = OD_OK;
    int i = 0;
    decoder_params_obj * params_obj = framework->param_table;

	/*根据启动任务名列表，创建实际任务*/
    ret = od_framework_load(framework, app_list, decoder_starting_list, sizeof(decoder_starting_list)/sizeof(task_name_t));

    /*连接任务间的tube*/
    for(i = 0; i < sizeof(decoder_connect_list)/sizeof(connect_str_t); i++)
    {
        ret = od_framework_connect(framework, decoder_connect_list[i].str);
        if(ret != OD_OK)
        {
            RPTERR("connect error; string is %s", decoder_connect_list[i].str);
            return OD_ERROR;
        }
    }
    
	/*从配置文件，加载所有参数*/
    jsparam_act_all(params_obj->decoder_json_hdl);
	
	/*启动所有线程任务*/
    ret = od_framework_start(framework, app_list, decoder_starting_list, sizeof(decoder_starting_list)/sizeof(task_name_t));

    return ret;
}

int32_t decoder_stop(od_framework_t * framework)
{
    int32_t ret = OD_OK;

    ret = od_framework_stop(framework, decoder_starting_list, sizeof(decoder_starting_list)/sizeof(task_name_t));
    RPT(RPT_WRN,"od_framework_stop end");

    return ret;
}

/*_*/

